#define _WIN32_DCOM
#include <Windows.h>
#include <atlbase.h>
#include <atlcom.h>
#include <atlctl.h>

#include <comdef.h>
#include <comutil.h>
#include <conio.h>
#include <iostream>
using namespace std;

#include "../atlhdc/ATLHDC_i.h"
#include "../atlhdc/ATLHDC_i.c"

void NewAndDelete(char ** lppStr)
{
	*lppStr = new char[10024];
}


HRESULT TestBSTR(IStructure * lpStructure)
{
	HRESULT hRes = S_OK;
	BSTR bstrOut = NULL;
	hRes = lpStructure->TestBSTR(0, NULL, &bstrOut);
	wprintf(bstrOut);
	::SysFreeString(bstrOut);
	return hRes;
}


HRESULT TestLONG(IStructure * lpStructure)
{
	HRESULT hRes = S_OK;
	LONG * lplOut = NULL;
	hRes = lpStructure->TestLONG(0, NULL, &lplOut);
	wprintf(L"%d", *lplOut);
	CoTaskMemFree(lplOut);
	return hRes;
}

HRESULT TestLPSTR(IStructure * lpStructure)
{
	HRESULT hRes = S_OK;
	LPSTR lpszOut = NULL;
	hRes = lpStructure->TestLPSTR(0, NULL, &lpszOut);
// 	printf("TestLPSTR");
	printf(lpszOut);
	CoTaskMemFree(lpszOut);
	return hRes;
}


HRESULT TestSPropTagArray(IStructure * lpStructure)
{
	HRESULT hRes = S_OK;
	_variant_t/*VARIANT*/ /*LPSPropTagArray*/ lpsptOut/* = NULL*/;
	hRes = lpStructure->TestSPropTagArray(20, NULL, &lpsptOut);
	SAFEARRAY *psa = lpsptOut.parray;
	for ( LONG i = 0; i < 20; ++i ) {
		_variant_t v1;
		hRes = SafeArrayGetElement(psa, &i, &v1);
		if ( hRes != S_OK ) {
			wprintf(L"fuck\n");
		}
		wprintf(L"out[%d]:0x%08x\n", i, v1.lVal);
	}
// 	wprintf(L"out[%d]:0x%08x\n", 9, lpsptOut.bstrVal);
// 	CoTaskMemFree(lpsptOut->aulPropTag);
// 	CoTaskMemFree(&lpsptOut);
	return hRes;
}


HRESULT TestVARIANT(IStructure * lpStructure)
{
	HRESULT hRes = S_OK;
	_variant_t v1("TestVARIANT");
	_variant_t v2("HDCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC");
	v2.Clear();
	hRes = lpStructure->TestVARIANT(0, v1, &v2);
	if ( VT_BSTR == v2.vt ) {
		wprintf(v2.bstrVal);
	}
	return hRes;
}


HRESULT TestSAFEARRAY(IStructure * lpStructure)
{
	HRESULT hRes = S_OK;

	SAFEARRAYBOUND bounds[1] = {0};
	bounds[0].cElements = 5;
	SAFEARRAY* psa = SafeArrayCreate(VT_VARIANT, 1, bounds);
	SAFEARRAY* psaOut = NULL;

	for(long i = 0; i < 5; i++)
	{
		_variant_t va(i + 0x1000);
		SafeArrayPutElement(psa, &i, &va);
	}

	_variant_t vsaIn;
	vsaIn.vt = VT_ARRAY | VT_BSTR;
	vsaIn.parray = psa;

	_variant_t vsaOut;

	hRes = lpStructure->TestSAFEARRAY(0, &vsaIn, &vsaOut);

	wprintf(vsaOut.bstrVal);

	SafeArrayDestroy(psa);



	return hRes;
}


HRESULT TestVARIANT_RECORD(IStructure * lpStructure)
{
	HRESULT hRes = S_OK;

	_variant_t vIn;
// 	vIn = "some string";
	CComPtr<ITypeLib> pTypeLib=NULL;
	CComPtr<ITypeInfo> pTypeInfo=NULL;
	CComPtr<IRecordInfo> pRecordInfo=NULL;
	hRes = LoadRegTypeLib(LIBID_ATLHDCLib, 1, 0, LANG_NEUTRAL, &pTypeLib); 
	hRes = pTypeLib->GetTypeInfoOfGuid(__uuidof(StudentStruct) /*StudentStruct_IID*/, &pTypeInfo); 
	hRes = GetRecordInfoFromTypeInfo(pTypeInfo, &pRecordInfo); 
	if(FAILED(hRes))
		return hRes;

	StudentStruct *data = new StudentStruct;
	data->name = 12/*SysAllocString(L"Some string")*/;
	data->value = 0x123;
	vIn.vt = VT_RECORD;
	vIn.pvRecord = (PVOID)data;
	vIn.pRecInfo = pRecordInfo;

	_variant_t vOut;
	hRes = lpStructure->TestVARIANT_RECORD(0, vIn, &vOut);
// 	if ( VT_RECORD == vOut.vt ) {
// 		CComPtr<IRecordInfo> pRF = vOut.pRecInfo;
// 		PVOID student = vOut.pvRecord;
// 		_variant_t vName;
// 		_variant_t vValue;
// 		pRF->GetField(student, L"name", &vName);
// 		if ( VT_BSTR == vName.vt ) {
// 			wprintf(vName.bstrVal);
// 		}
// 		pRF->GetField(student, L"value", &vValue);
// 	}
	return hRes;
}


HRESULT TestGetPropList(IStructure * lpStructure)
{
	HRESULT hRes = S_OK;
	LPSPropTagArrayT lpsptOut = NULL;
	hRes = lpStructure->GetPropList(0, NULL, &lpsptOut);
	for ( int i = 0; i < lpsptOut->cValues; ++i ) {
		std::cout << lpsptOut->aulPropTag[i] << std::endl;
	}
// 	CoTaskMemFree(lpsptOut->aulPropTag);
	CoTaskMemFree(lpsptOut);
	return hRes;
}


HRESULT TestGetProps(IStructure * lpStructure)
{
	HRESULT hRes = S_OK;
	LPSPropValueT spvOut = NULL;
	ULONG cValues;
	hRes = lpStructure->GetProps(0, NULL, &cValues, &spvOut);
	for ( int i = 0; i < 10; ++i ) {
		cout << hex;
		cout << "tag[" << i << "] = " << spvOut[i].ulPropTag << endl;
		cout << "value[" << i << "] = " << spvOut[i].Value.lpszA << endl;
// 		CoTaskMemFree(spvOut[i].Value.lpszA);
	}
// 	CoTaskMemFree(spvOut);
	MAPIFreeBuffer(spvOut);
	return hRes;
}


int main()
{
	try
	{
		// Initialize COM
		HRESULT hr = S_OK;
		if(	FAILED( hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED) ) ) {
			_com_issue_error(hr);
		}

		IStructure * lpStructure = NULL;
		hr = CoCreateInstance(
			CLSID_Structure, 
			NULL, 
			CLSCTX_ALL, 
			IID_IStructure, 
			(void**) &lpStructure);

		if ( FAILED( hr ) ) {
			_com_issue_error(hr);
		}

		LPSPropTagArrayT lpsptOut = NULL;
		for ( int i = 0; i < 100024; ++i ) {
			wprintf(L"\ni = %d\n", i);
			hr = TestGetProps(lpStructure);
// 			hr = TestGetPropList(lpStructure);
// 			hr = TestVARIANT_RECORD(lpStructure);
// 			hr = TestSAFEARRAY(lpStructure);
// 			hr = TestVARIANT(lpStructure);
// 			hr = TestSPropTagArray(lpStructure);
// 			hr = TestLPSTR(lpStructure);
// 			hr = TestBSTR(lpStructure);
// 			hr = TestLONG(lpStructure);

// 			hr = lpStructure->TestSPropTagArray(40, NULL, &lpsptOut);
// 			wprintf(L"out[%d]:0x%08x\n", i, lpsptOut->aulPropTag[i]);
// 			if ( hr != S_OK ) {
// 				hr = hr;
// 			}
// 			CoTaskMemFree(lpsptOut->aulPropTag);
// 			CoTaskMemFree(lpsptOut);
		}


		lpStructure->Release();

	}
	catch(_com_error &err)
	{
		wprintf(err.Description());
		CoUninitialize();
	}
	_getch();
	return 0;
}